package library

import (
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/jmoiron/sqlx"
	"log"
	"strconv"
	"strings"
)

type DbLibrary struct {
	_ctx         *gin.Context
	_db          *sqlx.DB
	_table       string
	_database    string
	_where       map[string][]any
	_field       []string
	_bind        []any
	_limit       int
	_currentPage int
	_total       int
	_lastPage    int
	_order       *string
	_by          *string
}

// NewDbLibrary 新建 db 类
func NewDbLibrary(ctx *gin.Context, db *sqlx.DB) *DbLibrary {
	return &DbLibrary{
		_db:    db,
		_ctx:   ctx,
		_where: make(map[string][]any),
		_field: []string{"*"},
		_limit: 15,
		_order: nil,
		_by:    nil,
	}
}

func (dl *DbLibrary) Table(table string) *DbLibrary {
	dl._table = table
	return dl
}

func (dl *DbLibrary) WhereEq(field string, value any) *DbLibrary {
	dl._where[field] = []any{"=", value}
	return dl
}

func (dl *DbLibrary) WhereLike(field string, value any) *DbLibrary {
	dl._where[field] = []any{"like", value}
	return dl
}

func (dl *DbLibrary) _getField() string {
	return strings.Join(dl._field, ",")
}

func (dl *DbLibrary) _getTable() string {
	return dl._table
}

func (dl *DbLibrary) _buildSql() (string, []any) {
	var bind []any
	sql := fmt.Sprintf("select %s from %s", dl._getField(), dl._getTable())
	var where []string
	for s, anies := range dl._where {
		where = append(where, fmt.Sprintf(" `%s` %s ? ", s, anies[0]))
		bind = append(bind, anies[1])
	}
	if len(where) > 0 {
		sql = fmt.Sprintf("%s where %s", sql, strings.Join(where, " and "))
	}
	//排序字段
	if dl._order != nil {
		by := "asc"
		if dl._by != nil {
			by = *dl._by
		}
		sql = fmt.Sprintf("%s order by %s %s", sql, *dl._order, by)
	}
	log.Printf("编译后要执行的sql语句:%s", sql)
	return sql, bind
}

func (dl *DbLibrary) _buildCountSql() (string, []any) {
	var bind []any
	sql := fmt.Sprintf("select %s from %s", "count(*) as cnt", dl._getTable())
	var where []string
	for s, anies := range dl._where {
		where = append(where, fmt.Sprintf(" `%s` %s ? ", s, anies[0]))
		bind = append(bind, anies[1])
	}
	if len(where) > 0 {
		sql = fmt.Sprintf("%s where %s", sql, strings.Join(where, " and "))
	}
	return sql, bind
}

func (dl *DbLibrary) WithOrderBy(order, by string) *DbLibrary {
	dl._order = &order
	dl._by = &by
	return dl
}

func (dl *DbLibrary) WithOrder(order string) *DbLibrary {
	dl._order = &order
	return dl
}

func (dl *DbLibrary) WithBy(by string) *DbLibrary {
	dl._by = &by
	return dl
}

func (dl *DbLibrary) Select(dest interface{}) error {
	sql, bind := dl._buildSql()
	return dl._db.Select(dest, sql, bind...)
}

func (dl *DbLibrary) WithLimit(limit int) *DbLibrary {
	dl._limit = limit
	return dl
}

func (dl *DbLibrary) Page(dest interface{}) error {
	sql, bind := dl._buildCountSql()

	var total int
	err := dl._db.Get(&total, sql, bind...)
	if err != nil {
		return errors.New("查询总数据量失败")
	}
	//查询一次总数
	dl._currentPage = dl._getPage()
	dl._lastPage = total / dl._limit

	sql, bind = dl._buildSql()

	sql = fmt.Sprintf("%s limit %d offset %d ;", sql, dl._limit, dl._limit*dl._currentPage)
	log.Printf("执行的分页查询sql:%s", sql)
	err = dl._db.Select(dest, sql, bind...)
	if err != nil {
		return err
	}
	return nil
}

func (dl *DbLibrary) _getPage() int {
	var p int
	page, ok := dl._ctx.GetQuery("page")
	if ok {
		ati, err := strconv.Atoi(page)
		if err == nil {
			p = ati
		}
	}
	return p
}

func (dl *DbLibrary) GetPageData(dest interface{}) gin.H {
	_ = dl.Page(dest)

	return dl.BuildPageData(dest)
}

func (dl *DbLibrary) BuildPageData(data interface{}) gin.H {
	return gin.H{
		"total":        dl._total,
		"per_page":     dl._limit,
		"current_page": dl._currentPage,
		"last_page":    dl._lastPage,
		"data":         data,
	}
}
